//
//  $Id: TreeTests.m 2 2007-09-07 18:35:43Z samson.etienne $
//  TCUBridgedClasses
//
//  Created by Simon Stapleton on Tue Oct 29 2002.
//  Copyright (c) 2001 Simon Stapleton. All rights reserved.
//

#import "TreeTests.h"
#import "TestExtendedTree.h"

@implementation TreeTests

- (void) testTreeCreation {
  id root;
  id node;

  id nodeData = [[NSArchiver alloc] init];
  
  STAssertNoThrow ([[TCUTree alloc] init], @"");
  
  STAssertThrows (root = [TCUTree treeWithObject:nil], @"Creating with nil should fail");
  STAssertNoThrow (root = [TCUTree treeWithObject:@"node"], @"Creating with a string shouldn't fail");
  
  STAssertNoThrow (node = [TCUTree treeWithObject:nodeData], @"");
  
  STAssertFalse (node == root, @"");
  STAssertFalse ([node isEqual:root], @"");
  
  STAssertNoThrow ([node copy], @"");
}

- (void) testAccessors {
  id node1 = [TCUTree treeWithObject:@"node1"];
  id node2 = [TCUTree treeWithObject:@"node2"];
  id node3 = [TCUTree treeWithObject:@"node3"];
  id node4 = [TCUTree treeWithObject:@"node4"];
  id node5 = [TCUTree treeWithObject:@"node5"];
  id node6 = [TCUTree treeWithObject:@"node6"];
  id node7 = [TCUTree treeWithObject:@"node7"];
  id array = [NSArray arrayWithObjects:node2, node3, node4, nil];
  
  STAssertNoThrow([node1 addChild:node2], @"");
  STAssertNoThrow([node1 addChild:node3], @"");
  STAssertNoThrow([node1 addChild:node4], @"");
  STAssertNoThrow([node2 addChild:node5], @"");
  STAssertNoThrow([node2 addChild:node6], @"");
  STAssertNoThrow([node3 addChild:node7], @"");

  STAssertTrue ([node1 childCount] == 3, @"");
  STAssertTrue ([node2 childCount] == 2, @"");
  STAssertTrue ([node3 childCount] == 1, @"");
  STAssertTrue ([node4 childCount] == 0, @"");
  STAssertFalse ([node1 isLeaf], @"");
  STAssertTrue ([node4 isLeaf], @"");

  STAssertTrue ([node1 root] == node1, @"");
  STAssertTrue ([node2 root] == node1, @"");

  STAssertTrue ([node1 parent] == nil, @"");
  STAssertTrue ([node2 parent] == node1, @"");
  
  STAssertTrue ([node1 firstChild] == node2, @"");
  STAssertTrue ([node1 lastChild] == node4, @"");
  STAssertTrue ([node1 childAtIndex:1] == node3, @"");
  STAssertThrows ([node1 childAtIndex:3], @"");
  STAssertTrue ([[node1 children] isEqual:array], @"");
  STAssertTrueNoThrow ([node1 containsChild:node3 recurse:NO], @"");
  STAssertFalseNoThrow ([node1 containsChild:node7 recurse:NO], @"");
  STAssertTrue ([node1 indexOfChild:node3] == 1, @"");
  STAssertTrue ([node1 indexOfChild:node7] == NSNotFound, @"");

  STAssertTrue ([node3 firstChild] == node7, @"");
  STAssertTrue ([node3 lastChild] == node7, @"");
  STAssertTrue ([node3 childAtIndex:0] == node7, @"");
  STAssertThrows ([node3 childAtIndex:1], @"");

  STAssertTrue ([node7 firstChild] == nil, @"");
  STAssertTrue ([node7 lastChild] == nil, @"");
  STAssertThrows ([node7 childAtIndex:0], @"");

  STAssertTrue ([node1 previousSibling] == nil, @"");
  STAssertTrue ([node1 nextSibling] == nil, @"");
  
  STAssertTrue ([node2 previousSibling] == nil, @"");
  STAssertTrue ([node2 nextSibling] == node3, @"");
  
  STAssertTrue ([node3 previousSibling] == node2, @"");
  STAssertTrue ([node3 nextSibling] == node4, @"");

  STAssertTrue ([node4 previousSibling] == node3, @"");
  STAssertTrue ([node4 nextSibling] == nil, @"");
  
  STAssertThrows ([node1 containsChild:nil recurse:YES], @"");
  
}

- (void) testMutating {
  id node1 = [TCUTree treeWithObject:@"node1"];
  id node2 = [TCUTree treeWithObject:@"node2"];
  id node3 = [TCUTree treeWithObject:@"node3"];
  id node4 = [TCUTree treeWithObject:@"node4"];

  STAssertNoThrow ([node1 addChild:node2], @"");
  STAssertTrue ([node1 childCount] == 1, @"");
  STAssertNoThrow ([node1 addChild:node3 atIndex:0], @"");
  STAssertTrue ([node1 childCount] == 2, @"");
  STAssertThrows ([node1 addChild:node4 atIndex:3], @"");
  STAssertTrue ([node1 childCount] == 2, @"");
  STAssertNoThrow ([node1 addChild:node4 atIndex:2], @"");
  STAssertTrue ([node1 childCount] == 3, @"");

  STAssertNoThrow ([node1 removeChild:node2], @"");
  STAssertTrue ([node1 childCount] == 2, @"");
  STAssertNoThrow ([node1 removeChild:node1], @"");
  STAssertTrue ([node1 childCount] == 2, @"");
  STAssertNoThrow ([node1 removeChildAtIndex:0], @"");
  STAssertTrue ([node1 childCount] == 1, @"");
  STAssertThrows ([node1 removeChildAtIndex:1], @"");
  STAssertTrue ([node1 childCount] == 1, @"");
  STAssertNoThrow ([node1 removeAllChildren], @"");
  STAssertTrue ([node1 childCount] == 0, @"");

  STAssertNoThrow ([node1 prependSibling:node2], @"");
  STAssertNoThrow ([node1 appendSibling:node2], @"");

  [node1 addChild:node2];

  [node2 prependSibling:node3];
  [node3 appendSibling:node4];

  STAssertTrue ([node2 previousSibling] == node4, @"");
  STAssertTrue ([node4 previousSibling] == node3, @"");
}


- (void) testGrafting {
  id node1 = [TCUTree treeWithObject:@"node1"];
  id node2 = [TCUTree treeWithObject:@"node2"];
  id node3 = [TCUTree treeWithObject:@"node3"];
  id node4 = [TCUTree treeWithObject:@"node4"];
  id node5 = [TCUTree treeWithObject:@"node5"];
  id node6 = [TCUTree treeWithObject:@"node6"];

  STAssertThrows([node1 graftOntoTree:node1], @"");

  [node1 addChild:node2];
  [node1 addChild:node3];
  [node1 addChild:node4];

  STAssertNoThrow([node1 graftOntoTree:node5], @"");
  STAssertTrue ([node1 parent] == node5, @"");

  
  STAssertThrows ([node1 graftOntoTree:node6 atIndex:1], @"");
  STAssertTrue ([node1 parent] == node5, @"");
  STAssertThrows ([node1 graftOntoTree:node2], @"");
  STAssertTrue ([node1 parent] == node5, @"");
  STAssertNoThrow ([node1 prune], @"");
  STAssertTrue ([node1 parent] == nil, @"");
  STAssertTrue ([node5 childCount] == 0, @"");
  
  STAssertThrows ([node1 graftOntoTree:nil], @"");
  
}

- (void) testCopying {
  id node1 = [TCUTree treeWithObject:@"node1"];
  id node2 = [TCUTree treeWithObject:@"node2"];
  id node3 = [TCUTree treeWithObject:@"node3"];
  id node4 = [TCUTree treeWithObject:@"node4"];
  id newNode;
  [node1 addChild:node2];
  [node1 addChild:node3];
  [node1 addChild:node4];

  newNode = [node1 copy];

  STAssertFalse (newNode == node1, @"");
  STAssertTrue ([newNode childCount] == [node1 childCount], @"");
  STAssertFalse ([newNode firstChild] == [node1 firstChild], @"");
}

- (void) testCoding {
  id node1 = [TCUTree treeWithObject:@"node1"];
  id node2 = [TCUTree treeWithObject:@"node2"];
  id node3 = [TCUTree treeWithObject:@"node3"];
  id node4 = [TCUTree treeWithObject:@"node4"];
  id theData;
  id newNode;
  [node1 addChild:node2];
  [node1 addChild:node3];
  [node1 addChild:node4];

  STAssertThrows (theData = [NSArchiver archivedDataWithRootObject:node1], @"");
  STAssertNoThrow (theData = [NSKeyedArchiver archivedDataWithRootObject:node1], @"");
  STAssertNoThrow (newNode = [NSKeyedUnarchiver unarchiveObjectWithData:theData], @"");

  STAssertTrue ([[newNode object] isEqual:[node1 object]], @"");
  STAssertTrue ([newNode childCount] == [node1 childCount], @"");
}

- (void) testFindingTrees {
  id node1 = [TCUTree treeWithObject:@"node1"];
  id node2 = [TCUTree treeWithObject:@"node2"];
  id node3 = [TCUTree treeWithObject:@"node3"];
  id node4 = [TCUTree treeWithObject:@"node4"];
  [node1 addChild:node2];
  [node1 addChild:node3];
  [node2 addChild:node4];

  STAssertEqualObjects ([node1 subtreeContainingObject:@"node1"], node1, @"");
  STAssertEqualObjects ([node1 subtreeContainingObject:@"node3"], node3, @"");
  STAssertEqualObjects ([node1 subtreeContainingObject:@"node4"], node4, @"");
  STAssertEqualObjects ([node1 subtreeContainingObject:@"pants"], nil, @"");
}

- (void) testFindingTreeEnhanced
{
    id dict1 = [NSDictionary dictionaryWithObject:@"node1" forKey:@"name"];
    id dict2 = [NSDictionary dictionaryWithObject:@"node2" forKey:@"name"];
    id dict3 = [NSDictionary dictionaryWithObject:@"node3" forKey:@"name"];
    id dict4 = [NSDictionary dictionaryWithObject:@"node4" forKey:@"name"];
    
    id node1 = [TCUTree treeWithObject:dict1];
    id node2 = [TCUTree treeWithObject:dict2];
    id node3 = [TCUTree treeWithObject:dict3];
    id node4 = [TCUTree treeWithObject:dict4];
    
    [node1 addChild:node2];
    [node1 addChild:node3];
    [node2 addChild:node4];
    
    STAssertEqualObjects ([node1 subtreeContainingObject:dict1], node1, @"");
    STAssertEqualObjects ([node1 subtreeContainingObject:dict3], node3, @"");
    STAssertEqualObjects ([node1 subtreeContainingObject:dict4], node4, @"");
    
    STAssertEqualObjects ([node1 subtreeContainingObject:[NSDictionary dictionaryWithObject:@"node2" forKey:@"name"]], node2, @"");
    STAssertEqualObjects ([node2 subtreeContainingObject:dict1], nil, @"");
}

- (void) testRetainCount {
  id node;
  id anotherNode;
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

// test basic retain/release

  node = [[TCUTree alloc] initWithObject:@"tree"];
  STAssertTrue ([node retainCount] == 1, @"");
  CFRetain (node);
  STAssertTrue ([node retainCount] == 2, @"Problem with CFRetain()");
  [node retain];
  STAssertTrue ([node retainCount] == 3, @"Problem with -retain");
  CFRelease (node);
  STAssertTrue ([node retainCount] == 2, @"Problem with CFRelease()");
  [node release];
  STAssertTrue ([node retainCount] == 1, @"Problem with -release");
  [node autorelease];
  STAssertTrue ([node retainCount] == 1, @"Problem with -autorelease");

  anotherNode = [[TCUTree alloc] initWithObject:@"another"];
  STAssertTrue ([anotherNode retainCount] == 1, @"");
  [node addChild:anotherNode];
  STAssertTrue ([node retainCount] == 1, @"");
  STAssertTrue ([anotherNode retainCount] == 2, @"");
  [anotherNode prune];
  STAssertTrue ([node retainCount] == 1, @"");
  STAssertTrue ([anotherNode retainCount] == 1, @"");

  [anotherNode addChild:node];
  STAssertTrue ([node retainCount] == 2, @"");
  STAssertTrue ([anotherNode retainCount] == 1, @"");
  
  STAssertNoThrow([pool release], @"");

  STAssertTrue ([anotherNode retainCount] == 1, @"");
  STAssertTrue ([node retainCount] == 1, @"");
  STAssertNoThrow([anotherNode release], @"");
}

- (void) testSubclassing {
    TCUTree *tester = [[TestExtendedTree alloc] initWithObject:@"Test1" dataString:@"Test2"];
    
    NSLog(@"%@", [tester dictionaryRepresentation]);
    STAssertNoThrow ([tester release], @"");
}

- (void) testLoading {
    
    id file = [[NSBundle bundleForClass:[TreeTests class]] pathForResource:@"treeSimpleData"
                                                                    ofType:@"plist"];
    id data = [NSData dataWithContentsOfFile:file];
    
    id dict = [NSPropertyListSerialization propertyListFromData:data
                                               mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                         format:NULL
                                               errorDescription:NULL];
    
    TCUTree *node = [[TCUTree alloc] initWithDictionary:dict];
    
    STAssertEqualObjects ([node object], @"Root", @"");
    STAssertEqualObjects ([[node childAtIndex:0] object], @"Node1", @"");
    STAssertEqualObjects ([[node childAtIndex:1] object], @"Node2", @"");

    STAssertTrue ([node childCount] == 2, @"");
    STAssertTrue ([[node childAtIndex:0] childCount] == 0, @"");
    STAssertTrue ([[node childAtIndex:1] childCount] == 1, @"");
    
    
    
    file = [[NSBundle bundleForClass:[TreeTests class]] pathForResource:@"treeExtendedData"
                                                                    ofType:@"plist"];
    data = [NSData dataWithContentsOfFile:file];
    
    dict = [NSPropertyListSerialization propertyListFromData:data
                                               mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                         format:NULL
                                               errorDescription:NULL];
    
    node = [[TCUTree alloc] initWithDictionary:dict];
    
    STAssertEqualObjects ([[node object] valueForKey:@"name"], @"Root", @"");
    STAssertEqualObjects ([[[node childAtIndex:0] object] valueForKey:@"name"], @"Node1", @"");
    STAssertEqualObjects ([[[node childAtIndex:1] object] valueForKey:@"name"], @"Node2", @"");
    
    STAssertTrue ([node childCount] == 2, @"");
    STAssertTrue ([[node childAtIndex:0] childCount] == 0, @"");
    STAssertTrue ([[node childAtIndex:1] childCount] == 1, @"");
}

- (void) testSaving
{
    id file = [[NSBundle bundleForClass:[TreeTests class]] pathForResource:@"treeSimpleData"
                                                                    ofType:@"plist"];
    id data = [NSData dataWithContentsOfFile:file];
    
    id dict = [NSPropertyListSerialization propertyListFromData:data
                                               mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                         format:NULL
                                               errorDescription:NULL];
    
    id node1 = [TCUTree treeWithObject:@"Root"];
    id node2 = [TCUTree treeWithObject:@"Node1"];
    id node3 = [TCUTree treeWithObject:@"Node2"];
    id node4 = [TCUTree treeWithObject:@"Node3"];
    
    [node1 addChild:node2];
    [node1 addChild:node3];
    [node3 addChild:node4];
    
    NSLog(@"%@", [node1 dictionaryRepresentation]);
    
    STAssertEqualObjects ([node1 dictionaryRepresentation], dict, @"");
    
    
}
@end
